package com.ibm.framework.exception.handler.monitor;

import java.util.List;
import java.util.Locale;
import java.util.ResourceBundle;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.core.Ordered;
import org.springframework.util.StringUtils;

import com.ibm.framework.exception.BaseException;
import com.ibm.framework.exception.event.MonitorExceptionMessageEvent;
import com.ibm.framework.exception.handler.ExceptionHandler;
import com.ibm.framework.exception.handler.ExceptionInfoExtractor;
import com.ibm.framework.exception.handler.ExceptionInfoFormater;
import com.ibm.framework.exception.model.ExceptionInfo;
import com.ibm.framework.exception.model.RawExceptionInfo;
import com.ibm.framework.exception.utils.ApplicationContextHolder;
import com.ibm.framework.exception.utils.NetUtil;

/**
 * 功能描述： 提取并格式化异常信息的监听器
 * 
 * @author v_pinzhao
 * 
 */
public class MonitorExceptionHandler implements InitializingBean, ExceptionHandler, Ordered {
    /**
     * 初始化序列值 default: same as non-Ordered
     */
    private int order = Integer.MIN_VALUE + 1;

    /**
     * 监听器系统key
     */
    private final String SYSTEMID_KEY = "monitor.systemid";

    /**
     * 监听器应用key
     */
    private final String APPID_KEY = "monitor.appid";

    /**
     * 系统id
     */
    private String systemId;

    /**
     * 应用id
     */
    private String appId;

    /**
     * 服务器ip
     */
    private String serverIp;

    /**
     * 配置文件
     */
    private String configfile = "monitor-api";

    /**
     * 异常代码
     */
    private String[] exceptionCodes;

    /**
     * 异常类型
     */
    private Class[] exceptionTypes;

    /**
     * 异常信息抽取器
     */
    private ExceptionInfoExtractor extractor;

    /**
     * 异常信息格式化工具
     */
    private ExceptionInfoFormater formater;

    /**
     * 异常处理
     * 
     * @param rawExceptionInfo 被提取的异常 信息
     */
    public void handle(RawExceptionInfo rawExceptionInfo) {
        if (null == rawExceptionInfo || null == rawExceptionInfo.getThrowable()) {
            return;
        }

        Throwable throwable = rawExceptionInfo.getThrowable();
        boolean monitor = false;
        if (throwable instanceof BaseException) {
            String exCode = ((BaseException) throwable).getCode();
            // 异常code是否是被监控异常code
            if (null != exCode && null != exceptionCodes) {
                for (String errorCode : exceptionCodes) {
                    if (exCode.toUpperCase().matches(errorCode) || exCode.toLowerCase().matches(errorCode)) {
                        monitor = true;
                        break;
                    }
                }
            }
        } else if (!(throwable instanceof BaseException) && null != exceptionTypes) {
            // 异常类是否是被监控的异常类型
            Class<? extends Throwable> exClass = throwable.getClass();
            for (Class exceptionClass : exceptionTypes) {
                if (exceptionClass.isAssignableFrom(exClass)) {
                    monitor = true;
                    break;
                }
            }
        }

        if (monitor) {
            ExceptionInfo exceptionInfo = extractor.extract(rawExceptionInfo);
            MonitorExceptionInfo monitorExceptionInfo = new MonitorExceptionInfo(exceptionInfo, systemId, appId,
                    serverIp);
            String monitorMessage = formater.getFormatString(monitorExceptionInfo);

            MonitorExceptionMessageEvent messageEvent = new MonitorExceptionMessageEvent(this, monitorMessage);
            ApplicationContext appContext = ApplicationContextHolder.getApplicationContext();
            appContext.publishEvent(messageEvent);
        }
    }

    /**
     * 异常信息提取并初始化 {@inheritDoc}
     */
    public void afterPropertiesSet() throws Exception {
        List<String> ipLst = NetUtil.getAllLocalIP();
        this.serverIp = StringUtils.collectionToDelimitedString(ipLst, ",");

        if (null == extractor) {
            extractor = new DefaultMonitorMessageExtractor();
        }

        if (null == formater) {
            formater = new MonitorMessageFormater();
        }

        if (!StringUtils.hasText(systemId) || !StringUtils.hasText(appId)) {
            Locale locale = Locale.getDefault();
            ResourceBundle confgResource = ResourceBundle.getBundle(configfile, locale);
            systemId = confgResource.getString(SYSTEMID_KEY);
            appId = confgResource.getString(APPID_KEY);
        }
    }

    /**
     * 设置顺序
     * 
     * @param order 顺序
     */
    public final void setOrder(int order) {
        this.order = order;
    }

    /**
     * 获取顺序
     * 
     * @return order
     */
    public final int getOrder() {
        return this.order;
    }

    /**
     * 设置异常code
     * 
     * @param exceptionCodes the exceptionCodes to set
     */
    public void setExceptionCodes(String[] exceptionCodes) {
        this.exceptionCodes = exceptionCodes.clone();
    }

    /**
     * 设置异常类型
     * 
     * @param exceptionTypes the exceptionTypes to set
     */
    public void setExceptionTypes(Class[] exceptionTypes) {
        this.exceptionTypes = exceptionTypes.clone();
    }

    /**
     * 设置格式化工具
     * 
     * @param formater the ExceptionInfoFormater to set
     */
    public void setFormater(ExceptionInfoFormater formater) {
        this.formater = formater;
    }

    /**
     * 设置配置文件
     * 
     * @param configfile the configfile to set
     */
    public void setConfigfile(String configfile) {
        this.configfile = configfile;
    }
}
